package com.gongpingjialoan.utility;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Comparator;

import com.gongpingjialoan.cc.Const;

import android.graphics.Bitmap;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;

/**
 * 磁盘缓存
 * 
 * @author kunee
 * 
 */
public class DiskCache implements ICache {

	private static final int MIN_FILE_SIZE_IN_BYTES = 100;
	static DiskCache diskCache = new DiskCache();
	File mStorageDirectory;

	boolean isEnabled = true;

	/**
	 * 初始化函数，若SD卡不可用，则磁盘缓存会被禁用
	 */
	private DiskCache() {
		try {
			mStorageDirectory = new File(Utils.getCacheDir());
			Log.d(this.toString(),
					"Path:" + mStorageDirectory.getAbsolutePath());
			smartFree();
		} catch (IOException e) {
			Log.d(this.toString(), "No Disk or disk error");
			isEnabled = false;
		}

	}

	public static DiskCache getInstance() {
		return diskCache;
	}

	/**
	 * 是否存在该文件,url为http://www.xxx.com/abc.jpg等
	 */
	public boolean exists(String url) {
		return isEnabled && getFile(url).exists();
	}

	/**
	 * 获取磁盘缓存文件，若无SD卡时返回null
	 */
	public File getFile(String url) {
		if (!isEnabled) {
			return null;
		}
		String hash = Utils.hashUrl(url);

		return new File(mStorageDirectory.getAbsolutePath() + File.separator
				+ hash);
	}

	/**
	 * 获取磁盘缓存文件输出流,url为http://www.xxx.com/abc.jpg等
	 */
	public InputStream getInputStream(String url) throws IOException {
		if (!isEnabled) {
			return null;
		}
		return (InputStream) new FileInputStream(getFile(url));
	}

	/**
	 * 缓存文件,url为http://www.xxx.com/abc.jpg等
	 */
	public void store(String url, InputStream is) {
		if (!isEnabled) {
			return;
		}
		is = new BufferedInputStream(is);
		try {
			OutputStream os = new BufferedOutputStream(new FileOutputStream(
					getFile(url)));

			byte[] b = new byte[2048];
			int count;
			int total = 0;

			while ((count = is.read(b)) > 0) {
				os.write(b, 0, count);
				total += count;
			}
			os.close();
		} catch (IOException e) {
			return;
		}
	}

	/**
	 * 缓存对象,若为LIST，MAP类型则直接序列化
	 * 
	 * @param url
	 * @param obj 可序列化的对象
	 */
	public void store(String key,final Object value){
		if(!isEnabled){
			return;
		}
		if(value == null){
			return;
		}
		ObjectOutputStream out = null;
		try{
			out = new ObjectOutputStream(     
                    new FileOutputStream(getFile(key)));
			out.writeObject(value);
		}catch(Exception e){
			Log.e(this.toString(),"缓存对象到SD卡错误",e);
		}finally{
			if(out != null){
				try{out.close();}catch(Exception e){}
			}
		}
	}
	
	public Object get(String key){
		ObjectInputStream in = null;
		try    
        {     
            in = new ObjectInputStream(
            		new FileInputStream(getFile(key)));
            
            return in.readObject();
        } catch (Exception e){
        } finally{
        	if(in != null){
        		try{in.close();}catch(Exception e){}
        	}
        }
		return null;
	}
	
	/**
	 * 缓存图像，url为http://www.xxx.com/abc.jpg等
	 * 
	 * @param url
	 * @param bitmap
	 */
	public void store(String url, Bitmap bitmap) {
		if (!isEnabled) {
			return;
		}
		OutputStream out = null;
		try {
			File newFile = getFile(url);
			out = new FileOutputStream(newFile);
			if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)) {
				out.flush();
				out.close();
			}
		} catch (IOException e) {
			return;
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (Exception e) {
				}
			}
		}
	}

	/**
	 * 从缓存中移除
	 */
	public void invalidate(String url) {
		if (!isEnabled) {
			return;
		}
		getFile(url).delete();
	}

	/**
	 * 清理一些下载失败或者非法的小文件
	 */

	public void cleanup() {
		if (!isEnabled) {
			return;
		}
		String[] children = mStorageDirectory.list();
		if (children != null) { // children will be null if hte directyr does
								// not exist.
			for (int i = 0; i < children.length; i++) {
				File child = new File(mStorageDirectory, children[i]);
				if (child.length() <= MIN_FILE_SIZE_IN_BYTES) {
					child.delete();
				}
			}
		}
	}

	public void smartFree() {
		// 若磁盘空间不足，则自动清理一部分
		if (!isEnabled) {
			return;
		}

		File[] files = mStorageDirectory.listFiles();
		if(files==null)
		{
			return;
		}
		/**
		 * 小于1000个文件暂不清理缓存
		 */
		if (files.length < Const.SIMPLE_CLEAR_CACHE_NUM) {
			return;
		}

		int dirSize = 0;
		for (int i = 0; i < files.length; i++) {
			dirSize += files[i].length();
		}
		/**
		 * 缓存过大或者磁盘空间太小时触发文件清理
		 */
		if (dirSize > Const.MAX_CACHE_SIZE
				|| Const.MIN_AVAILABLE_CACHE_SIZE > freeSpaceOnSd()) {

			// 先清理40%
			int removeFactor = (int) ((0.4 * files.length) + 1);

			Arrays.sort(files, new FileLastModifSort());

			Log.i("ImageFileCache", "清理缓存文件");
			for (int i = 0; i < removeFactor; i++) {
				files[i].delete();
			}
		}
	}

	/**
	 * 磁盘剩余空间
	 * 
	 * @return
	 */
	private int freeSpaceOnSd() {
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
				.getPath());
		double sdFreeSize = ((double) stat.getAvailableBlocks() * (double) stat
				.getBlockSize());
		return (int) sdFreeSize;
	}

	/**
	 * TODO 根据文件的最后修改时间进行排序 *
	 */
	private class FileLastModifSort implements Comparator<File> {
		public int compare(File arg0, File arg1) {
			if (arg0.lastModified() > arg1.lastModified()) {
				return 1;
			} else if (arg0.lastModified() == arg1.lastModified()) {
				return 0;
			} else {
				return -1;
			}
		}
	}

}
